package com.company.common.api.wrap;

import java.lang.reflect.Method;
import java.util.Objects;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.AnnotationUtils;

import com.company.cloud.common.bean.BaseParam;
import com.company.cloud.common.bean.LoginSimpleUserInfo;
import com.company.cloud.common.constant.BaseReturnEnum;
import com.company.cloud.common.exception.BusinessException;
import com.company.cloud.common.utils.AuthContextUtils;
import com.company.cloud.common.utils.SpringContextUtils;
import com.company.common.api.wrap.annotation.ApiWrap;
import com.company.common.api.wrap.handler.WrapHandler;

@Aspect
@Primary
public class ApiWrapAspect {

	@Pointcut("@within(com.company.common.api.wrap.annotation.ApiWrap) || @annotation(com.company.common.api.wrap.annotation.ApiWrap)")
	public void apiWrapPointcut() {

	}

	@Before("apiWrapPointcut()")
	public void before(JoinPoint joinPoint) {
		MethodSignature sign = (MethodSignature) joinPoint.getSignature();
		Method method = sign.getMethod();
		ApiWrap wrapAnnotation = AnnotationUtils.findAnnotation(method, ApiWrap.class);
		if (wrapAnnotation == null) {
			wrapAnnotation = AnnotationUtils.findAnnotation(joinPoint.getTarget().getClass(), ApiWrap.class);
		}
		Objects.requireNonNull(wrapAnnotation);
		
		Class<?> clazz = wrapAnnotation.value();
		WrapHandler wrapHandler = (WrapHandler) SpringContextUtils.getBean(clazz);
		Object[] args = joinPoint.getArgs();
		for(Object obj:args) {
			if (obj instanceof BaseParam) {
				BaseParam request = (BaseParam) obj;
				this.verify(wrapHandler, request);
			}
		}

	}

	private void verify(WrapHandler wrapHandler, BaseParam request) {

		//
		long timestamp = request.getTimestamp();
		wrapHandler.isLegalTime(timestamp);

		String nonce = request.getNonceStr();
		String signatureParam = request.getSign();
		
		LoginSimpleUserInfo userInfo = AuthContextUtils.getUserNoValidate();
		String appSecret = userInfo == null ? null : userInfo.getKey();

		//
		wrapHandler.isReplayAttack(appSecret, timestamp, nonce, signatureParam);

		String signature = wrapHandler.getSignature(appSecret, request);

		if (!signatureParam.equals(signature)) {
			throw new BusinessException(BaseReturnEnum.SIGN_ERROR);
		}

	}

}
